#include <iostream>
#include <string.h>
using namespace std;

/*
  ex02 数组的介绍
  01 = 数组声明 和 sizeof
  02 = 指针和数组 (针算术运算 || 通过指针遍历 || *(++p1) || 区别) 
  03 = 字符串数组说明
  
  fun01 - int 数组 转 字符串

*/

void intArrayToString(int *array, int length,char *result);


int main(void)
{
  // -----------------------  01 = 数组声明 和 sizeof --------------------------------------

  // 声明数组，需要指明数组元素的类型和数量。
  int arr[12] = {1, 2, 3, 4, 5};

  // 如果初始化式比数组短，那么数组中剩余的元素赋值为0：

  // 初始化式完全为空是非法的，所以要在大括号内放上一个0。
  int arr2[10] = {0}; // 数组初始化为全0

  // 运算符sizeof
  // 确定数组的大小（字节数）。如果数组a有10个整数，那么sizeof(a)通常为40（假定每个整数占4个字节）。

  // 得到数组长度
  int length = sizeof(arr) / sizeof(arr[0]);

  cout << "001 - arr数组长度 " << length << endl;

  char result[100] = {0};
  intArrayToString(arr,length,result); //数组名在传递给函数时，总是被视为指针。
  cout <<"002 - arr数组内容 - 原始数据" << result << endl;

  // -----------------------  02 = 指针和数组 (针算术运算 || 通过指针遍历 || *(++p1) || 区别) --------------------------------------
  int *p = &arr[5];
  *p = 6;
  intArrayToString(arr,length,result);
  cout <<"003 - arr数组内容 - 指针修改数组" << result << endl;

  //通过在p上执行指针算术运算（或者地址算术运算）可以访问数组a的其他所有元素。
  //·指针加上整数；·指针减去整数；·两个指针相减。

  int *p1;
  //指针加上整数
  p1 = p + 1;

  *p1 = 7;
  intArrayToString(arr,length,result);
  cout <<"004 - arr数组内容 - 指针进行算术运算" << result << endl;  

  //只有在两个指针指向同一个数组时，把它们相减才有意义
  int distance = p1 - p;
  cout <<"005 - 两个指针的距离" << distance << endl;  

  int sum = 0;

  int *p2;

  p2 = &arr[length - 1]; //数组最后一个元素的地址
  *p2 = 100;
  intArrayToString(arr,length,result);
  cout <<"006 - arr数组内容 - 最后一个元素" << result << endl;  

  //通过指针地址遍历 ,进行求和 || 元素arr[length]不存在,因为数组的下标是 (0 到 length -1) ,但是地址是存在的,循环不会尝试检查arr[length]
  for(p2 = &arr[0]; p2 < &arr[length]; p2++ ){
    sum += *p2;
  }

  cout <<"007 - 遍历指针求和" << sum << endl;  

  //*运算符和++运算符的组合  因为后缀++的优先级高于*，所以编译器把上述语句看成是 *(++p1) = 8;
  *++p1 = 8;
  intArrayToString(arr,length,result);
  cout <<"008 - arr数组内容 - *运算符和++运算符的组合" << result << endl;  

  //*++p *p++ (*p)++ 这几个区别见文档和书


  //指针的算术运算是数组和指针之间相互关联的一种方法 
  //另一种关键的关系： 
  
  //**** 可以用数组的名字作为指向数组第一个元素的指针 ***
  *arr = 10;
  *(arr + 1) = 20;
  intArrayToString(arr,length,result);
  cout <<"009 - arr数组内容 - 数组名作为指针" << result << endl;  

  //使用数组名简化循环 
  sum = 0;
  for(p2 = arr; p2 < arr + length; p2++ ){
    sum += *p2;
  }
  cout <<"010 - 使用数组名简化循环 求和" << sum << endl;  

  //区别
  // 虽然可以把数组名用作指针，但是不能给数组名赋新的值。试图使数组名指向其他地方是错误的： arr++;
  // 我们可以把a复制给一个指针变量，然后改变该指针变量： p2 = arr; p2++;


  // -----------------------  03 = 字符串数组说明 --------------------------------------
  /*
  
    存储字符串数组的最佳方式是什么？最明显的解决方案是创建二维的字符数组，然后按照每行一个字符串的方式把字符串存储到数组中。
    char planets[][8] = {"abc","sss002","12345678"}

    C语言要求指明列数。
    并非所有的字符串都足以填满数组的一整行，所以C语言用空字符来填补。
    
    
    上面的方式有一点浪费空间
    我们需要的是参差不齐的数组（ragged array），即每一行有不同长度的二维数组。C语言本身不提供这种“参差不齐的数组类型”

    另一种方式
    建立一个特殊的数组，这个数组的元素都是指向字符串的指针。

    指向字符串的指针的数组：
    char *planets[] = {"abc","sss002","12345678"};
  */

  //字符串常量（通常是文字字符串）转换为一个char*类型，这在C++中是不被允许的。所以加const
  const char *planets[] = {"abc","sss002","12345678"};

  for (size_t i = 0; i < 3; i++)
  { 
    //和访问二维数组方式相同
    if(planets[i][0] == '1'){
      cout << "011 - 遍历字符串数组,得到1开头的在字符串: " << planets[i] << endl;  
    }
  }
  


  return 1;
}






//fun01 - int 数组 转 字符串
void intArrayToString(int *array, int length , char *result)
{
  char numberBuffer[12]; // 为32位整数足够的大小

  result[0] = '\0'; // 初始化结果字符串

  for (int i = 0; i < length; i++)
  {
    sprintf(numberBuffer, "%d", array[i]); // 将整数转为字符串
    strcat(result, numberBuffer);          // 拼接到结果字符串中

    if (i < length - 1)
    {
      strcat(result, ","); // 添加分隔符
    }
  }
}